/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bff.spi.action.retrievedefault;

import com.inspur.edp.bef.api.lcp.IStandardLcp;
import com.inspur.edp.bff.api.dataprocessor.IDefaultValueConvertor;
import com.inspur.edp.bff.api.exception.BffFrameworkException;
import com.inspur.edp.bff.api.exception.ErrorCodes;
import com.inspur.edp.bff.api.extend.IBffEntityExtend;
import com.inspur.edp.bff.api.extend.IBffManagerExtend;
import com.inspur.edp.bff.api.manager.IFSManager;
import com.inspur.edp.bff.api.manager.SourceConfig;
import com.inspur.edp.bff.api.manager.context.RetrieveDefaultContext;
import com.inspur.edp.bff.entity.defaultvalue.VoDefaultValue;
import com.inspur.edp.bff.spi.builtin.BffEntityResInfoImpl;
import com.inspur.edp.bff.spi.builtin.BffModelResInfoImpl;
import com.inspur.edp.bff.spi.builtin.BffPropertyInfo;
import com.inspur.edp.bff.spi.defaultvalue.DefaultValueUtil;
import com.inspur.edp.bff.spi.utils.BffActionNames;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.ModelResInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefEntityResInfoImpl;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefModelResInfoImpl;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DefaultRetrieveDefaultAction extends AbstractRetrieveDefaultAction {


    public DefaultRetrieveDefaultAction(RetrieveDefaultContext context) {
        super(context);
    }

    @Override
    protected void execute() {
        ArrayList<SourceConfig> sourceConfigs = getContext().getSourceConfigs();
        if (sourceConfigs == null || sourceConfigs.size() == 0) {
            throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_2034);
        }
        VoDefaultValue defaultValue = getRetrieveDefaultContext().getVoDefaultValue();
        String dataId = getRetrieveDefaultContext().getDataId();
        IEntityData beData = null;
        IDefaultValueConvertor convertor = getContext().getDefaultValueConvertor();
        if (this.getModelInfo() instanceof BffModelResInfoImpl) {
            beData = retrieveDefaultNew(defaultValue, dataId, convertor);
        } else {
            beData = retrieveDefaultOld(defaultValue, dataId, convertor);
        }
        getRetrieveDefaultContext().getRetrieveDefaultData().put(BffActionNames.DefaultName, new ArrayList<IEntityData>(Arrays.asList(new IEntityData[]{beData})));
    }

    private ModelResInfo getModelInfo() {
        return this.getContext().getModelResourceInfo();
    }

    private IEntityData retrieveDefaultOld(VoDefaultValue defaultValue, String dataId, IDefaultValueConvertor convertor) {
        IStandardLcp lcp = getLcp();
        if (defaultValue != null && convertor != null) {
            Map<String, Object> beDefault = null;
            ModelResInfo info = getContext().getBffManager().getModelInfo();
            if (info != null && info instanceof CefModelResInfoImpl) {
                BffEntityResInfoImpl resInfo = (BffEntityResInfoImpl) info.getCustomResource(info.getRootNodeCode());
                BffPropertyInfo propertyInfo = (BffPropertyInfo) resInfo.getEntityTypeInfo().getPropertyInfos().values().toArray()[0];
                if (StringUtils.isNullOrEmpty(propertyInfo.getBeLabelId())) {
                    beDefault = convertor.convertFromVo(defaultValue);
                } else {
                    beDefault = DefaultValueUtil.transVoDefaultValueToBe(getContext(), defaultValue, null);
                }
            } else
                beDefault = convertor.convertFromVo(defaultValue);
            return lcp.retrieveDefault(beDefault);
        } else if (!StringUtils.isNullOrEmpty(dataId)) {
            return lcp.retrieveDefault(dataId);
        } else {
            return lcp.retrieveDefault();
        }
    }

    private IEntityData retrieveDefaultNew(VoDefaultValue defaultValue, String dataId, IDefaultValueConvertor convertor) {
        Map<String, Object> defaultValues = new HashMap<>();
        Map<String, Object> beDefault = null;
        IFSManager bffManager = getContext().getBffManager();
        IStandardLcp lcp = getContext().getLcp();
        initDefaultValue(bffManager, lcp, defaultValues, null);
        if ((defaultValue != null && convertor != null)) {
            ModelResInfo info = bffManager.getModelInfo();
            if (info != null && info instanceof CefModelResInfoImpl) {
                BffEntityResInfoImpl resInfo = (BffEntityResInfoImpl) info.getCustomResource(info.getRootNodeCode());
                BffPropertyInfo propertyInfo = (BffPropertyInfo) resInfo.getEntityTypeInfo().getPropertyInfos().values().toArray()[0];
                if (StringUtils.isNullOrEmpty(propertyInfo.getBeLabelId())) {
                    beDefault = convertor.convertFromVo(defaultValue);
                } else {
                    beDefault = DefaultValueUtil.transVoDefaultValueToBe(getContext(), defaultValue, null);
                }
            } else {
                beDefault = convertor.convertFromVo(defaultValue);
            }
        }
        //合并默认值
        mergeDefaultValue(beDefault, defaultValues);

        if (!StringUtils.isNullOrEmpty(dataId)) {
            return getLcp().retrieveDefault(dataId, defaultValues);
        } else {
            return getLcp().retrieveDefault(defaultValues);
        }
    }

    public void mergeDefaultValue(Map<String, Object> outerValue, Map<String, Object> innerDefaultValue) {
        if (outerValue == null || outerValue.size() == 0)
            return;
        for (Map.Entry<String, Object> defaultValue : outerValue.entrySet()) {
            innerDefaultValue.put(defaultValue.getKey(), defaultValue.getValue());
        }
    }

    private void initDefaultValue(IFSManager manager, IStandardLcp lcp, Map<String, Object> values, ArrayList<String> nodeCodes) {
        initBasicDefaultValue(manager, lcp, values, nodeCodes);
        List<IBffManagerExtend> extendList = manager.getBffContext().getExtList();
        if (extendList == null || extendList.size() == 0)
            return;
        initChangedDefaultValue(manager, lcp, values, extendList, nodeCodes);
        mapExtendDefaultValue(manager, extendList, values);
    }

    private void mapExtendDefaultValue(IFSManager manager, List<IBffManagerExtend> extendList, Map<String, Object> values) {
        Map<String, Object> extendDefaultValues = new HashMap<>();
        Map<String, Object> beDefaultValues = new HashMap<>();
        for (IBffManagerExtend bffManagerExtend : extendList) {
            IBffEntityExtend bffEntityExtend = bffManagerExtend.getDataTypeExtend();
            //处理变更默认值
            initExtendDefaultValue(manager, bffEntityExtend, extendDefaultValues);
            //转换扩展默认值
            bffManagerExtend.mapDefaultValuesFromVo(extendDefaultValues, beDefaultValues);
            //合并默认值
            mergeDefaultValue(beDefaultValues, values);
        }
    }

    private void initExtendDefaultValue(IFSManager manager, IBffEntityExtend extend, Map<String, Object> values) {
        CefEntityResInfoImpl entityResInfo = extend.getEntityResInfo();
        if (entityResInfo == null || entityResInfo.getEntityTypeInfo() == null || entityResInfo.getEntityTypeInfo().getPropertyInfos() == null)
            return;
        Map<String, DataTypePropertyInfo> propertyInfos = entityResInfo.getEntityTypeInfo().getPropertyInfos();
        for (Map.Entry<String, DataTypePropertyInfo> propInfo : propertyInfos.entrySet()) {
            DataTypePropertyInfo propertyInfo = propInfo.getValue();
            if (propertyInfo.getDefaultValue() == null || ("".equals(propertyInfo.getDefaultValue().getRealValue()) || propertyInfo.getDefaultValue().getRealValue() == null))
                continue;
            DefaultValueUtil.dealExtendValue(manager, propertyInfo, null, values);
        }
    }

    private void initBasicDefaultValue(IFSManager manager, IStandardLcp lcp, Map<String, Object> values, ArrayList<String> nodeCodes) {
        CefEntityResInfoImpl resInfo = (CefEntityResInfoImpl) manager.getModelInfo().getCustomResource(getContext().getBffManager().getModelInfo().getRootNodeCode());
        if (resInfo.getEntityTypeInfo() == null || resInfo.getEntityTypeInfo().getPropertyInfos() == null || resInfo.getEntityTypeInfo().getPropertyInfos().size() == 0)
            return;
        dealBasicPropDefaultValue(manager, lcp, resInfo.getEntityTypeInfo().getPropertyInfos(), values, nodeCodes);
    }

    private void initChangedDefaultValue(IFSManager manager, IStandardLcp lcp, Map<String, Object> values, List<IBffManagerExtend> extendList, ArrayList<String> nodeCodes) {
        for (IBffManagerExtend bffManagerExtend : extendList) {
            IBffEntityExtend bffEntityExtend = bffManagerExtend.getDataTypeExtend();
            dealChangePropertyValue(manager, lcp, bffEntityExtend, values, nodeCodes);
        }
    }

    private void dealChangePropertyValue(IFSManager manager, IStandardLcp lcp, IBffEntityExtend bffEntityDataExtend, Map<String, Object> values, ArrayList<String> nodeCodes) {
        bffEntityDataExtend.mapChangedDefaultValuesFromVo(manager, lcp, nodeCodes, values);
    }

    private void dealBasicPropDefaultValue(IFSManager manager, IStandardLcp lcp, Map<String, DataTypePropertyInfo> prpertyInfos, Map<String, Object> values, ArrayList<String> nodeCodes) {
        for (Map.Entry<String, DataTypePropertyInfo> propertyInfo : prpertyInfos.entrySet()) {
            DataTypePropertyInfo propertyInfoTemp = propertyInfo.getValue();
            String beLabelId = ((BffPropertyInfo) propertyInfoTemp).getBeLabelId();
            if (defaultValueIsNull(propertyInfoTemp))
                continue;
            if (beLabelId == null || "".equals(beLabelId))
                continue;
            DefaultValueUtil.dealDefaultValue(manager, lcp, propertyInfoTemp, nodeCodes, values);
        }
    }

    private boolean defaultValueIsNull(DataTypePropertyInfo propertyInfo) {
        if (propertyInfo.getDefaultValue() == null)
            return true;
        Object value = propertyInfo.getDefaultValue().getRealValue();
        if (value == null || "".equals(value))
            return true;
        return false;
    }
}
